/** ****************************************************************************
@addtogroup Wheel
@{
*******************************************************************************/

#ifndef _WHEEL_H_
#define _WHEEL_H_

#include "nonos.h"
#include "button.h"


/// 旋钮档位间隔多久就认为是旋转结束(ms)
#define WHEEL_LAZY_INTERVAL	300

/// 旋钮旋转停止后回调函数原型
typedef void (*FUNC_onWheelSteps)(uint8_t isWheelDown, int steps, uint totalSteps, void *cookie);
/// 旋钮旋转一步回调函数原型
typedef void (*FUNC_onWheelStep)(s8 dir, void *cookie);

/// 旋钮驱动类
typedef struct {
	// 档位数量
	uint8_t totalGears;
	
	/// 是否处于监听状态
	uint8_t listen;
	
	/// 每档对应的I/O口状态
    FUNC_GPIO_IsInOn funcPinAIsOn;
    FUNC_GPIO_IsInOn funcPinBIsOn;
	FUNC_GPIO_IsInOn funcIsDown;

	/// 上一次中断时的状态，用于判断旋钮是否被转动了
	uint8_t spinState;
	/// 开始旋转时的按钮状态(是否按下)
	uint8_t downOnSpin;
	/// 已经旋转的档位数(>0表示正转，<0表示反转)
	s8 steps;
	/// 开始旋转时的时间戳(ms)
	uint32_t spinBeginTime;
	
	/// 按键状态机
	uint8_t btnState;
	/// 按钮按下时间
	uint32_t btnDownTime;

	// Button “按下”事件回调函数
	FUNC_void_voidp onDown;
	void* cookieDown;
	uint8_t onDownTriggered;

	// Button “弹起”事件回调函数
	FUNC_void_voidp onUp;
	void* cookieUp;

	// Button “点击”事件回调函数
	FUNC_void_voidp onClick;
	void* cookieClick;

	// Button “长按1”事件回调函数
	FUNC_void_voidp onLongPress1;
	void* cookieLongPress1;
	uint8_t onLongPress1Triggered;

	// Button “长按2”事件回调函数
	FUNC_void_voidp onLongPress2;
	void* cookieLongPress2;
	uint8_t onLongPress2Triggered;

    /// “正/反转”事件回调函数
    FUNC_onWheelStep onStep;
    void* cookieStep;

    /// “旋转了多档”事件回调函数
    FUNC_onWheelSteps onSteps;
    void* cookieSteps;

	/// @brief 旋钮状态检查任务
	OSTaskId taskIdWheel;
	/// @brief 按钮状态轮询任务
	OSTaskId taskIdBtn;
} driver_wheel_t;

/// @brief 初始化
/// @param funcIsDown 按钮是否被按下
/// @param funcPinAIsOn 旋钮 A 脚状态
/// @param funcPinBIsOn 旋钮 B 脚状态
void wheel_init(driver_wheel_t* dev, uint8_t totalGears, FUNC_u8_void funcIsDown, FUNC_GPIO_IsInOn funcPinAIsOn, FUNC_GPIO_IsInOn funcPinBIsOn);

/// @brief 挂接事件回调函数
void wheel_setupCallbacks(
	driver_wheel_t* dev, 
	FUNC_void_voidp   onDown,       void* cookieDown,
	FUNC_void_voidp   onUp,         void* cookieUp,
	FUNC_void_voidp   onClick,      void* cookieClick,
	FUNC_void_voidp   onLongPress1, void* cookieLongPress1,
	FUNC_void_voidp   onLongPress2, void* cookieLongPress2,
    FUNC_onWheelSteps onSpinSteps,  void* cookieSteps,
    FUNC_onWheelStep  onStep,       void* cookieStep );

/// @brief 监听
void wheel_listen(driver_wheel_t* dev, bool enable);

/// @brief A/B 脚 EXTI 中断处理
/// @param isPinA 是否是 A 脚
/// @attention 应用程序必须把按钮 A 或 B 脚配置为上升沿和下降沿双向中断，并在对应的 GPIO EXTI 中断中，调用此函数 !!!
void wheel_spinIrqHandler(driver_wheel_t* dev, uint8_t isPinA);


#endif  // _WHEEL_H_
/// @}
